/* SAT satisfication
* 1.SAT问题
    给定 n 个变量，每个变量的取值只有两种： {0,1} 。然后给定若干个限制，每个限制的形式为 {xi=0/1}∨{xj=0/1}，
    表示 ”xi为 0/1” 或 ” xj为 0/1” 至少有一项成立。问你对于每个变量是否存在一组取值使得每个限制同时满足

* 2.2-SAT问题
    每个条件包含两个命题的SAT问题
    如：对于x1,x2,x3使得x1∨x3,¬x2∨x3成立

    转化：建图
    用xi表示xi=True，用¬xi表示xi=False用图论里的每一个点表示每一个命题，每一条边表示每两个命题间的推导关系
    推导关系：a→b <-> ¬a∨b a,b∈{True,False} 即：a∨b <-> ¬a→b <-> ¬b→a 那么可以把每一个条件表示为图论中的两条边了

    解的情况
    无解：xi→⋯→xi∧¬xi→…xi即xi和¬xi在同一个强连通分量里，说明xi不管取真或假都是相反的，这就有问题了
    有解：枚举所有xi，缩点找强连通分量，当xi所在的强连通分量的拓扑排序在¬x所在的强连通分量的拓扑排序之后时，取x为true

* 本题:
    a[i]=0 a[i+1]=1
*/

#define DEBUG
#pragma GCC optimize("O1,O2,O3,Ofast")
#pragma GCC optimize("no-stack-protector,unroll-loops,fast-math,inline")
#pragma GCC target("avx,avx2,fma")
#pragma GCC target("sse,sse2,sse3,sse4,sse4.1,sse4.2,ssse3")

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=2000010, M=2000010, INF=0x3f3f3f3f;

int n, m;
int h[N], e[M], ne[M], idx;
int dfn[N], low[N], timestamp, stk[N], top;
int scc[N], cnt;
bool instk[N];
/*
    dfn[N]：时间戳数组，dfn[u] 表示节点 u 在深度优先搜索中第一次被访问的时间戳。时间戳从 1 开始递增。
    low[N]：追溯值数组，low[u] 表示节点 u 及其子孙节点能够追溯到的最早的时间戳。
    timestamp：时间戳计数器，初始值为 0，每次访问一个新节点时，timestamp 加 1。
    stk[N]：栈数组，用于存储当前正在访问的节点。在深度优先搜索过程中，将节点依次压入栈中。
    top：栈顶指针，初始值为 0，表示栈为空。
    scc[N]：强连通分量编号数组，scc[u] 表示节点 u 所属的强连通分量的编号。强连通分量的编号从 1 开始递增。
    cnt：强连通分量的数量，初始值为 0。
    instk[N]：标记数组，instk[u] 表示节点 u 是否在栈中。
*/

void AddEdge(int a, int b)
{
    e[idx]=b, ne[idx]=h[a], h[a]=idx++;
}

void Tarjan(int u)
{
    dfn[u] = low[u] = ++timestamp;
    stk[++top]=u, instk[u]=true;
    for(int i=h[u]; ~i; i=ne[i])
    {
        int v=e[i];
        if(!dfn[v])
        {
            Tarjan(v);
            low[u]=min(low[u], low[v]);
        } 
        else if(instk[v]) low[u]=min(low[u], dfn[v]);
    }

    if(low[u] == dfn[u])
    {
        int v;
        cnt++;
        do
        {
            v=stk[top--], instk[v]=false, scc[v]=cnt;
        } while (v != u);
        
    }
}

int main()
{
    #ifdef DEBUG
        freopen("./in.txt","r",stdin);
    #else
        ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    #endif

    memset(h, -1, sizeof h);
    cin >> n >> m;

    while(m--)
    {
        int u, v, a, b; cin >> u >> a >> v >> b; //xu=a xv=b
        u--, v--; //从0开始
        AddEdge((u<<1) ^ !a, (v<<1) ^ b);
        AddEdge((v<<1) ^ !b, (u<<1) ^ a);

        // AddEdge(u*2 + !a, v*2 + b);
        // AddEdge(v*2 + !b, u*2 + a);
    }    

    for(int i=0; i<n<<1; i++)
        if(!dfn[i]) Tarjan(i);
    
    for(int i=0; i<n; i++)
        if(scc[i<<1]==scc[(i<<1)^1])
        {
            puts("IMPOSSIBLE");
            return 0;
        }
    puts("POSSIBLE");
    for(int i=0; i<n; i++)
        if(scc[i<<1]<scc[(i<<1)^1]) printf("0 ");
        else printf("1 ");
    return 0;
}